home *** CD-ROM | disk | FTP | other *** search
Text File | 1996-09-17 | 15.7 KB | 514 lines | [TEXT/MPS ] |
- //========================================================================================
- //
- // File: FWLnkDst.cpp
- // Release Version: $ ODF 2 $
- //
- // Copyright: (c) 1993 - 1996 by Apple Computer, Inc., all rights reserved.
- //
- //========================================================================================
-
- #include "FWFrameW.hpp"
-
- #ifndef FWLNKDST_H
- #include "FWLnkDst.h"
- #endif
-
- // ----- Framework Includes -----
-
- #ifndef FWPART_H
- #include "FWPart.h"
- #endif
-
- #ifndef FWPRESEN_H
- #include "FWPresen.h"
- #endif
-
- #ifndef FWLNKITE_H
- #include "FWLnkIte.h"
- #endif
-
- #ifndef FWCLNINF_H
- #include "FWClnInf.h"
- #endif
-
- #ifndef FWINTER_H
- #include "FWInter.h"
- #endif
-
- #ifndef FWCLPCMD_H
- #include "FWClpCmd.h"
- #endif
-
- #ifndef FWLNKCMD_H
- #include "FWLnkCmd.h"
- #endif
-
- #ifndef FWSESION_H
- #include "FWSesion.h"
- #endif
-
- // ----- Foundation Includes -----
-
- #ifndef FWPRIDEB_H
- #include "FWPriDeb.h"
- #endif
-
- #ifndef FWBARRAY_H
- #include "FWBArray.h"
- #endif
-
- #ifndef FWMEMMGR_H
- #include "FWMemMgr.h"
- #endif
-
- // ----- OpenDoc Includes -----
-
- #ifndef SOM_Module_OpenDoc_StdProps_defined
- #include <StdProps.xh>
- #endif
-
- #ifndef SOM_Module_OpenDoc_StdTypes_defined
- #include <StdTypes.xh>
- #endif
-
- #ifndef SOM_ODStorageUnit_xh
- #include <StorageU.xh>
- #endif
-
- #ifndef SOM_ODSession_xh
- #include <ODSessn.xh>
- #endif
-
- #ifndef SOM_ODLink_xh
- #include <Link.xh>
- #endif
-
- //========================================================================================
- // Runtime information
- //========================================================================================
-
- #ifdef FW_BUILD_MAC
- #pragma segment odflinking
- #endif
-
- //========================================================================================
- // Template Instantiations
- //========================================================================================
-
- FW_DEFINE_AUTO_TEMPLATE(FW_TOrderedCollectionIterator, FW_CLinkDestination)
- FW_DEFINE_AUTO_TEMPLATE(FW_TOrderedCollection, FW_CLinkDestination)
-
- #ifdef FW_USE_TEMPLATE_PRAGMAS
-
- #pragma template_access public
- #pragma template FW_TOrderedCollection<FW_CLinkDestination>
- #pragma template FW_TOrderedCollectionIterator<FW_CLinkDestination>
-
- #endif
-
- //========================================================================================
- // class FW_CLinkDestination
- //========================================================================================
-
- //----------------------------------------------------------------------------------------
- // FW_CLinkDestination::FW_CLinkDestination
- //----------------------------------------------------------------------------------------
-
- FW_CLinkDestination::FW_CLinkDestination(Environment* ev,
- ODLink* odLink,
- ODLinkInfo* linkInfo,
- FW_CPresentation* presentation)
- : FW_CLink(ev, presentation),
- fODLink(NULL),
- fPart(NULL),
- fCommandWaitingToEndAction(NULL),
- fRegistered(false),
- fEstablished(false),
- fEmbed(false),
- fDataInterchange(presentation->GetPart(ev)->GetDataInterchange(ev))
- {
- if (odLink)
- {
- fODLink = odLink;
- odLink->Acquire(ev);
- }
-
- // Copy link info
- fLinkInfo = *linkInfo;
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CLinkDestination::~FW_CLinkDestination
- //----------------------------------------------------------------------------------------
-
- FW_CLinkDestination::~FW_CLinkDestination()
- {
- FW_SOMEnvironment ev;
- this->Unregister(ev);
- if (fODLink)
- fODLink->Release(ev);
-
- if (fEmbed) // fEmbedInfo is valid
- FW_MPasteAsHandler::PrivDisposeEmbedInfoFields(&fEmbedInfo);
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CLinkDestination::PrivEstablishLink
- //----------------------------------------------------------------------------------------
-
- void FW_CLinkDestination::PrivEstablishLink(Environment* ev)
- {
- this->LinkEstablished(ev);
- fEstablished = true;
-
- if (fRegistered && !fLinkInfo.autoUpdate)
- this->Unregister(ev);
-
- if (fCommandWaitingToEndAction)
- {
- fCommandWaitingToEndAction->PrivAddEndAction(ev);
- fCommandWaitingToEndAction = NULL;
- }
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CLinkDestination::LinkEstablished
- //---------------------------------------------------------------------------------------
- void FW_CLinkDestination::LinkEstablished(Environment* ev)
- {
- FW_UNUSED(ev);
- // Override to change the status of embedded frames to kODInLinkDestination
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CLinkDestination::LinkUpdated
- //----------------------------------------------------------------------------------------
-
- void FW_CLinkDestination::LinkUpdated(Environment* ev, ODUpdateID id)
- {
- ODLinkKey linkKey;
- if (!fODLink->Lock(ev, 0, &linkKey))
- return;
-
- /* The following Try-block is for when OpenDoc throws an exception in GetContentStorageUnit.
- If a cross-document link was just created, LinkUpdated gets called before the link content SU
- has received any data. In that case we want to just let the exception fall on the floor.
- LinkUpdated will be called again after the link data has been written.
- */
- ODStorageUnit* su;
- FW_VOLATILE(linkKey);
- FW_TRY
- {
- su = fODLink->GetContentStorageUnit(ev, linkKey); /* cross-doc link will fail the 1st time */
- }
- FW_CATCH_BEGIN
- FW_CATCH_REFERENCE(FW_XException, ex)
- {
- fODLink->Unlock(ev, linkKey);
- // If GetContentStorageUnit returned the error kODErrNoLinkContent,
- // the last source update failed; don't update the link at this time.
- if (ex.GetPlatformError() == kODErrNoLinkContent)
- return;
- FW_THROW_SAME();
- }
- FW_CATCH_END
-
- FW_Boolean updateSuccessful = false;
- FW_TRY
- {
- if (this->DoUpdateLink(ev, su, fEmbed ? &fEmbedInfo : NULL)) // part-specific
- {
- // --- Update the link info ---
-
- // When updating a manual link, id is a new id, to avoid possible link cycle
- // dialog. But the link info needs the original id from the source so that
- // the 'Update Now' button in link info dlg will be propery enabled or disabled
- // next time the dialog is displayed.
-
- fLinkInfo.change = this->GetODLink(ev)->GetUpdateID(ev);
- fLinkInfo.changeTime = fODLink->GetChangeTime(ev);
- updateSuccessful = true;
- }
- else // Couldn't update the link, for some reason
- if (!fEstablished)
- FW_Failure(kODErrCannotEstablishLink);
- }
- FW_CATCH_BEGIN
- FW_CATCH_EVERYTHING()
- {
- // error occurred in DoUpdateLink somewhere
- fODLink->Unlock(ev, linkKey);
- FW_THROW_SAME();
- }
- FW_CATCH_END
-
- // --- We're done with the link content SU ---
- fODLink->Unlock(ev, linkKey);
-
- // This used to be conditional upon !fEstablished, so only was executed on the first update.
- // But it sets the link status of embedded frames, which needs done each time. Other stuff
- // that should only be done the first time turns out to be a no-op in subsequent updates anyway.
- // But caution: What is done is part specific, so each linking part should assume that
- // LinkEstablished will be called after every update.
-
- this->PrivEstablishLink(ev);
-
- // --- Propagate changes to source links maintained by the part ---
- if (updateSuccessful)
- this->DoPropagateChanges(ev, id);
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CLinkDestination::DoPropagateChanges
- //----------------------------------------------------------------------------------------
- void FW_CLinkDestination::DoPropagateChanges(Environment* ev, ODUpdateID updateID)
- {
- // Content in the specified destination link has changed.
- // Override to propagate changes to source links maintained by this part (part-specific)
-
- // --- Notify all containing parts of the change ---
- fPresentation->ContentUpdated(ev, updateID);
-
- fPresentation->Invalidate(ev); // force all frames to be redrawn
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CLinkDestination::Register
- //----------------------------------------------------------------------------------------
- void FW_CLinkDestination::Register(Environment* ev, FW_CPart* itsPart)
- {
- if (fRegistered)
- return;
-
- // For a manual link, this may still be needed if the user changes it to
- // automatic. It really aught to be passed to the constructor.
- FW_ASSERT(itsPart != kODNULL);
- fPart = itsPart;
-
- ODUpdateID linkUpdateID = fODLink->GetUpdateID(ev);
- FW_Boolean needsUpdate = (fLinkInfo.change != linkUpdateID);
-
- if (!fEstablished || fLinkInfo.autoUpdate)
- {
- fRegistered = TRUE;
-
- //--- Register for automatic updates ---
- // First determine if another link with the same ODLink as ours already registered
- FW_Boolean alreadyRegistered = FALSE;
- FW_CPartLinkDestIterator iter(itsPart);
- for (FW_CLinkDestination* link = iter.First(); iter.IsNotComplete(); link = iter.Next())
- {
- if ((link != this) && fODLink->IsEqualTo(ev, link->GetODLink(ev))
- && link->IsRegistered(ev))
- {
- alreadyRegistered = TRUE;
- break;
- }
- }
-
- if (!alreadyRegistered)
- {
- fODLink->RegisterDependent(ev, fPart->GetODPart(ev), fLinkInfo.change);
- // part::LinkUpdated call will be generated
- needsUpdate = FALSE;
- }
- }
-
- if (needsUpdate) // Manually update now
- this->LinkUpdated(ev, linkUpdateID);
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CLinkDestination::Unregister
- //----------------------------------------------------------------------------------------
- void FW_CLinkDestination::Unregister(Environment* ev)
- {
- if (!fRegistered) return;
-
- // Unregister, if this is the last automatically updated destination of the link in the part
- FW_ASSERT(fPart);
- short regCount = 0;
- FW_CPartLinkDestIterator iter(fPart);
- for (FW_CLinkDestination* link = iter.First(); iter.IsNotComplete(); link = iter.Next())
- {
- if (link->IsRegistered(ev) && fODLink->IsEqualTo(ev, link->GetODLink(ev)))
- regCount++;
- }
-
- if (regCount == 1) // this is the only registered link
- {
- fODLink->UnregisterDependent(ev, fPart->GetODPart(ev));
- }
-
- fRegistered = FALSE;
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CLinkDestination::BreakLink
- //----------------------------------------------------------------------------------------
- void FW_CLinkDestination::BreakLink(Environment* ev)
- {
- this->Unregister(ev);
- fEstablished = false;
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CLinkDestination::RestoreLink
- //----------------------------------------------------------------------------------------
- void FW_CLinkDestination::RestoreLink(Environment* ev, FW_CPart* part)
- {
- // Re-register the link if necessary
- this->Register(ev, part);
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CLinkDestination::ExternalizeLink
- //----------------------------------------------------------------------------------------
- void FW_CLinkDestination::ExternalizeLink(Environment* ev, ODStorageUnit* storageUnit,
- FW_CCloneInfo* cloneInfo)
- {
- //-- Storage unit must be focused to property kODPropContents, value destLinkFormat
- ODStorageUnitRef suRef;
- fODLink->Externalize(ev);
-
- ODID linkID = fODLink->GetID(ev);
- if (cloneInfo != NULL)
- {
- linkID = cloneInfo->Clone(ev, linkID, 0, 0);
- }
-
- // May not have been able to clone the link
- if (linkID == kODNULL) return;
-
- //--- Write the link version number ---
- long version = FW_kLinkVersionNumber;
- FW_CByteArray byteArray(&version, sizeof(long));
- storageUnit->SetValue(ev, byteArray);
-
- //--- Write a reference to the link ---
- storageUnit->GetStrongStorageUnitRef(ev, linkID, suRef);
- byteArray.Set(&suRef, sizeof(ODStorageUnitRef));
- storageUnit->SetValue(ev, byteArray);
-
- //--- Write link info ---
- ODType savedKind = fLinkInfo.kind; // save kind string
- fLinkInfo.kind = (ODType) strlen(savedKind) + 1;
- byteArray.Set(&fLinkInfo, sizeof(ODLinkInfo));
- storageUnit->SetValue(ev, byteArray); // write out linkinfo
- byteArray.Set((void*)savedKind, (ODULong)fLinkInfo.kind);
- storageUnit->SetValue(ev, byteArray); // write out kind string
- fLinkInfo.kind = savedKind; // restore kind string
-
- //--- Write embed info, if any ---
- byteArray.Set(&fEmbed, sizeof(FW_Boolean));
- storageUnit->SetValue(ev, byteArray);
- if (fEmbed)
- {
- //-- save strings, except for selectedKind, which was written above
- savedKind = fEmbedInfo.translateKind; // save translateKind string
- if (savedKind != NULL)
- fEmbedInfo.translateKind = (ODType) strlen(savedKind) + 1;
- ODEditor savedEditor = fEmbedInfo.editor; // save editor string
- if (savedEditor != NULL)
- fEmbedInfo.editor = (ODType) strlen(savedEditor) + 1;
-
- //-- write fields of fEmbedInfo
- byteArray.Set(&fEmbedInfo, sizeof(ODPasteAsResult));
- storageUnit->SetValue(ev, byteArray);
- if (savedKind != NULL) // write the translateKind string
- {
- byteArray.Set((void*)savedKind, (ODULong)fEmbedInfo.translateKind);
- storageUnit->SetValue(ev, byteArray);
- }
- if (savedEditor != NULL) // write the editor string
- {
- byteArray.Set((void*)savedEditor, (ODULong)fEmbedInfo.editor);
- storageUnit->SetValue(ev, byteArray);
- }
-
- //-- Restore string ptrs to fEmbedInfo
- fEmbedInfo.translateKind = savedKind;
- fEmbedInfo.editor = savedEditor;
- }
-
- //--- Write out data specific to this part's link ---
- this->DoExternalizeLink(ev, storageUnit, cloneInfo);
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CLinkDestination::SavePasteAsSettings
- //----------------------------------------------------------------------------------------
- void FW_CLinkDestination::SavePasteAsSettings(Environment* ev, ODPasteAsResult& pasteAsResult)
- {
- FW_UNUSED(ev);
- // Record the PasteAs dialog settings, so links can be updated appropriately
- fLinkInfo.kind = pasteAsResult.selectedKind; // Copy the pointer
- fEmbed = (pasteAsResult.mergeSetting == kODFalse);
- if (fEmbed)
- {
- // Embed As: remember the user's settings
- fEmbedInfo = pasteAsResult;
- // Set pointer fields to NULL so they won't be disposed by the caller
- pasteAsResult.translateKind = NULL;
- pasteAsResult.editor = NULL;
- }
-
- pasteAsResult.selectedKind = NULL; // so caller doesn't dispose it
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CLinkDestination::GetContainingFrame
- //----------------------------------------------------------------------------------------
- FW_CFrame* FW_CLinkDestination::GetContainingFrame(Environment* ev, ODFrame* odEmbeddedFrame)
- {
- FW_UNUSED(ev);
- FW_UNUSED(odEmbeddedFrame);
-
- // Should be overridden if the part supports linking and embedding.
- // Return the containing frame if odEmbeddedFrame is involved in this link.
- // Called when finding the source of a link.
-
- return NULL;
- }
-
- //----------------------------------------------------------------------------------------
- // FW_CLinkDestination::ShowLinkInfo
- //----------------------------------------------------------------------------------------
- void FW_CLinkDestination::ShowLinkInfo(Environment* ev, FW_CFrame* frame, FW_CLinkManager* linkMgr)
- {
- ODLinkInfoResult infoResult;
- if (fODLink->ShowLinkDestinationInfo(ev, frame->GetActiveFacet(ev), &fLinkInfo, true, &infoResult))
- {
- switch (infoResult.action)
- {
- case kODLinkInfoFindSource:
- fODLink->ShowSourceContent(ev);
- break;
-
- case kODLinkInfoBreakLink:
- {
- // Create and return an undoable command to break the link
- FW_CBreakLinkCommand* cmd = FW_NEW(FW_CBreakLinkCommand, (ev, frame, this, linkMgr));
- cmd->Execute(ev);
- }
- break;
-
- case kODLinkInfoUpdateNow:
- this->LinkUpdated(ev, FW_CSession::UniqueUpdateID(ev));
- break;
-
- case kODLinkInfoOk:
- if (infoResult.autoUpdate != fLinkInfo.autoUpdate)
- {
- fLinkInfo.autoUpdate = infoResult.autoUpdate;
- if (fLinkInfo.autoUpdate)
- this->Register(ev, fPart);
- else
- this->Unregister(ev);
- }
- break;
- }
- }
- }
-
-